package com.github.utils;

import org.apache.log4j.Logger;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>{@link File}相关工具类</p>
 * @author  Crab2Died
 */
public class FileUtils {

    private static final Logger logger      = Logger.getLogger(HttpUtils.class);

    private static final int    BUFFER_SIZE = 2 << 14;

    /**
     * <p>递归ZIP压缩文件并写入文件流</p>
     * @author  Crab2Died
     *
     * @param out  {@link ZipOutputStream}ZIP文件输出流
     * @param f    待压缩文件或文件夹
     * @param base 偏移文件夹
     * @param bo   {@link BufferedOutputStream}缓冲输出流
     * @throws IOException
     */
    static
    private void zip(ZipOutputStream out, File f, String base, BufferedOutputStream bo) throws IOException {

        if (f.isDirectory()) {
            File[] fl = f.listFiles();
            if (fl == null || fl.length == 0) {
                // 创建zip压缩进入点base
                out.putNextEntry(new ZipEntry(base + File.separator));
            } else {
                for (File aFl : fl) {
                    // 递归遍历子文件夹
                    zip(out, aFl, base + File.separator + aFl.getName(), bo);
                }
            }
        } else {
            // 创建zip压缩进入点base
            try (FileInputStream in = new FileInputStream(f);
                 BufferedInputStream bi = new BufferedInputStream(in)) {
                out.putNextEntry(new ZipEntry(base));
                byte[] bytes = new byte[BUFFER_SIZE];
                int read;
                while ((read = bi.read(bytes, 0, BUFFER_SIZE)) != -1) {
                    // 将字节流写入当前zip目录
                    bo.write(bytes, 0, read);
                }
            }
        }
    }

    /**
     * <p>指定的文件夹下的全部文件ZIP压缩至指定的文件路径下</p>
     * @author  Crab2Died
     *
     * @param zipFileName 输出ZIP文件路径
     * @param inputFile   待压缩文件路径
     * @throws IOException
     */
    static
    private void zip(String zipFileName, File inputFile) throws IOException {

        logger.info(String.format("compressing [%s] >> [%s]", inputFile.getPath(), zipFileName));
        long start = System.currentTimeMillis();
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFileName));
             BufferedOutputStream bos = new BufferedOutputStream(zos)) {
            zip(zos, inputFile, inputFile.getName(), bos);
        }
        long end = System.currentTimeMillis();
        logger.info(String.format("compressed [%s] >> [%s], time consuming : %s msec",
                inputFile.getName(),
                zipFileName,
                (end - start)));
    }

    /**
     * <p>指定的文件夹下的全部文件ZIP压缩至指定的文件路径下</p>
     * @author  Crab2Died
     *
     * @param os         输出ZIP文件流
     * @param targetPath 待压缩文件路径
     * @throws IOException
     */
    static
    public void zip(OutputStream os, String targetPath) throws IOException {

        logger.info(String.format("[%s] compressing ... >> ", targetPath));
        long start = System.currentTimeMillis();
        try (ZipOutputStream zos = new ZipOutputStream(os);
             BufferedOutputStream bos = new BufferedOutputStream(zos);) {
            File targetFile = new File(targetPath);
            zip(zos, targetFile, targetFile.getName(), bos);
        }
        long end = System.currentTimeMillis();
        logger.info(String.format("<< compressed [%s], time consuming : %s msec",
                targetPath,
                (end - start)));
    }

}
